20230503 estsoft - python function, list

Function

버그나 잘못된 입력에 강인한 함수를 만들어 오래오래 쓸 수 있도록 만드는 것이 함수 만들기의 관건! 수업 끝나고 돌아보니 사실 인자에 타입을 명시하기만 하면 되는 문제인 것 같기도 하고.

타입을 명시한다고 반드시 그 타입만 들여보내는 게 아니었다. 그냥 사용자 편의 조각에 불과하고, 사실 다른 타입 변수를 넣어도 에러 없이 들어가 최후의 상황에 터진다... 💣💣💣

def plus(num1, num2):
	try:
		return num1 + num2
	except:
		return float('inf')

error handling with parameters

이를 막기 위해서 프로그래머는 몇가지 선택권이 주어진다(회사 컨벤션이 있다면 없을지도)

  1. isinstance 를 활용한 타입체크
  2. pydantic 모듈을 활용한 미연에 발생할 수 있는 타입에러 잡아주기 | pydantic 공식문서
  3. 적극적인 try, except구문 활용
def plus_with_type(num1: int, num2: int) -> int:
    if isinstance(num1, int) and isinstance(num2, int):
        return num1 + num2
    raise TypeError('only int values are allowed')

위니브 대표님의 의견은 파이썬이 파이썬할 뿐이라는 것 같다. 각자 고유한 패러다임이 있는거고, 그걸 가지고 다른 언어와 비교하고 까내리는 것은 삼가자.

타입힌트는 나중에 하지만 강제하진 않습니다. 저는 개인적으로 typehint도 견고한 코드를 위해 좋지만, pythonic함은 감소된다 생각해요.

재귀함수

아래 코드는 재귀를 활용한 (효율적인) 지수 연산이다.

def my_pow(num1, num2):
    if num2 == 0:
        return 1
    if num2 % 2 == 0:
        half = my_pow(num1, num2 // 2)
        return half * half
    else:
        half = my_pow(num1, num2 // 2)
        return half * half * num1

# test
for exp in range(40):
    print(f'2 ** {exp} = {my_pow(2, exp)}')
    assert 2 ** exp == my_pow(2, exp)

Closure, 함수가 함수를 리턴한다

아래는 지수 연산을 수행하는 또 하나의 방법을 표현한다. Factory Function이라고도 불리우는 이 방식은, 휘발되지 않는 x 를 가지고 함수를 만든 뒤에 나중에 가서 호출하는 방식으로 이루어진다.

def 제곱(x):
    def 승수(y):
        return x ** y
    return 승수


pow3 = 제곱(3)
pow3_4 = pow3(4)

Local variables and Global variables

  1. 전역변수 선언 시 함수 내에서 접근은 가능하지만 수정이 되지 않는다.
  2. 전역변수를 함수 내에서 수정하기 위해선 global 을 작성하면 된다. 실무에서 거의 사용 안한다고 하넹

함수 내에서 사용되는 로컬 변수들의 변수명, 현재 값 등을 알고 싶을 때 locals 내장함수를 사용할 수 있다.

def one():
    x = 1
    def two():
        print(x)
        print(locals())
    print(locals())
    two()
one()

Lists

컨벤션 자료형(dict, tuple, set, list)의 경우 같은 값이 있을 경우 같은 곳을 가리키게 설계되어 있다.

l = [1, 999, 999, 999, 1, 1, 999, 1]
assert id(l[0]) == id(l[4]) == id(l[5])
assert id(l[1]) == id(l[2]) == id(l[3]) == id(l[6])

List Operations and Methods

# Those are acceptable in my mind
x = [10] * 3
print(x)
x[0] = 999
print(x)

# But things get weird
x = [[10] * 2] * 3
print(x)
# [[10, 10], [10, 10], [10, 10]]
x[0][0] = 999
print(x)
# [[999, 10], [999, 10], [999, 10]]

# What on earth? I meant the result would be [[999, 10], [10, 10], [10, 10]]
# but when you look into ids,,,
assert id(x[0][0]) == id(x[1][0]) == id(x[2][0])